#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "splay.h"

#include <QVBoxLayout>
#include <QFileDialog>
#include <QMessageBox>
#include <fstream>
//#include <QFile>
//#include <QTextStream>
#include <QDebug>

#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
#include <cstdlib> // exit()

using namespace std;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle("单词统计");
    ui->input->setPlaceholderText("请输入要查询词频的文件名");
}

MainWindow::~MainWindow()
{
    delete ui;
}


class Word {
public:
    Word() {
        freq = 1;   // 单词出现的频率
    }
    int operator== (const Word& ir) const {
        return strcmp(word, ir.word) == 0;
    }
    int operator< (const Word& ir) const {
        return strcmp(word, ir.word) < 0;
    }
private:
    char* word;
    int freq;
    friend class WordSplay;  // 单词树需要访问单词里的数据，肯定要做友元，给单词树权限呀
    //friend ostream& operator<< (ostream&, const Word&);
};

// 继承伸展树，每个节点都是一个单词word，包括它的词频信息
class WordSplay : public SplayTree<Word> {
public:
    WordSplay() {
        differentWords = wordCnt = 0;
    }
    QString run(QTextStream&, const QString& fileName);
private:
    int differentWords, // 文件去重后的所有单词树
    wordCnt;        // 文件中所有单词树
    void visit(SplayingNode<Word>*); // 访问单词
};

// 树中的节点都不重复，所以differentWords单词要++，所有单词不只是+1，而是加上当前访问的节点单词的出现次数freq
void WordSplay::visit(SplayingNode<Word>* p) {
    differentWords++;
    wordCnt += p->info.freq;
}

QString WordSplay::run(QTextStream& in, const QString& fileName) {
    QStringList words;
    Word rec;
    while (!in.atEnd()) {
        // 跳过不是字母的符号
        QChar firstChar;
        do {
            in >> firstChar;
        } while (!in.atEnd() && !in.status() && !firstChar.isLetter());
        // 文件读完，退出外层循环
        if (in.atEnd())
            break;
        // 循环读取字符，读取一个单词
        QString word;
        word.append(firstChar.toUpper());
        while (!in.atEnd() && !in.status()) {
            QChar nextChar;
            in >> nextChar; // 从输入流读取一个字符
            qDebug() << "为什么不打印？  " << nextChar;
            if(nextChar.isLetter()){
                word.append(nextChar.toUpper()); // 由于题目指出不区分大小写，所以都将字符转换为大写
                qDebug() << "一个词啊  " << word;
            }else{
                break;
            }
        }
        // 一个单词读取结束，加个分隔符
        words.append(word);
        qDebug() << words.length();
        for(int i = 0; i < words.length(); i++){
            qDebug() << "list中的单个word： " << words[i];
        }
        // 给这个单词 word 动态分配内存空间
        if (!(rec.word = new char[word.length() + 1])) {
            qCritical() << "No room for new nodes\n";
            throw std::bad_alloc();
        }
        // 成功分配好空间后，将 word 内容拷贝进 rec.word 里
        qstrcpy(rec.word, word.toUtf8().constData());
        // 在树中搜索，看单词是否已经存在，存在就会返回该节点->info的指针
        Word* p = search(rec);
        // 不存在就插入新单词
        if (p == 0)   insert(rec);
        else  p->freq++;   // 存在就让其词频++
    }

    // 中序遍历
    inorder();

    // 打印总单词数和不重复的单词数

    qDebug() << "\n\nFile " << fileName
             << " contains " << wordCnt << "or" << words.length() << " words among which "
             << differentWords << " are different\n";

    qDebug() << "单词总数:  " + QString::number(wordCnt) + " 不重复个数： " + QString::number(differentWords);
    return "单词总数:  " + QString::number(wordCnt) + "\n" + "不重复个数： " + QString::number(differentWords);
}


void MainWindow::on_confirm_btn_clicked()
{
    // 输出当前工作路径
    QString currentDir = QDir::currentPath();
    qDebug() << "Current Working Directory: " << currentDir;
    // 获取输入框中的内容
    QString fileName = ui->input->text();
    // 输入框没写内容
    if (fileName.isEmpty()) {
        QMessageBox::warning(this, "Error", "Please enter a file name.");
        return;
    }
    // 创建一个伸展树和文件对象
    WordSplay splayTree;
    QFile file(fileName);
    QString res = "";
    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        // 创建QTextStream对象，将in和文件file关联
        QTextStream in(&file);
        // 直接传入QTextStream流和文件名，进行词频计算等主要逻辑操作
        res = splayTree.run(in, fileName);
        file.close();
    } else {  // 找不到文件
        QMessageBox::warning(this, "Error", "File not found.");
    }
    // 将输入逻辑放到这里，显示到文本框中
    ui->show->setPlainText(res);
}

void MainWindow::on_exit_btn_clicked()
{
    close();
}
